Skip to content

feat(core): extracted the scenario runner - #1

Merged
schronck merged 4 commits into
mainfrom
feat/core/scenario-runner
Oct 14, 2026
Merged

schronck merged 4 commits into
mainfrom
feat/core/scenario-runner

Conversation

@schronck

Copy link
Copy Markdown
Collaborator

What

This PR adds the first version of penelope, a Given/When/Then scenario runner for systems that become consistent over time.

Why

decentralization-manager wrote its integration suite in a runner that lived in crates/decman/tests/common/. Other repos could not use the runner without copying it. This crate holds the generic part, so any repo can add it as a git dependency.

How it works

  • A Scenario runs its steps in order. A Given or When step runs once. A Then step polls a probe every 2 seconds until the probe passes, fails, or reaches its deadline.
  • A probe records each failure in a ProbeDiag. The runner stops a step early when the same fatal failure repeats 3 times. On a timeout, the error includes the last recorded failure.
  • A small Fixture trait replaces decman's concrete fixture type. The trait has one method, which returns the fixture's ProbeDiag.

Key decisions

  • Only the generic core moved. decman keeps its fixture, its Canton helpers, its ~50 phases, and its HTTP failure rules. The 404 rule depends on how decman's frontend answers, so the rule stays in decman.
  • StepKind is private. Nothing outside the runner uses it, so the public API stays small.
  • The README is the crate documentation. Its example runs as a doctest, so the example cannot drift from the code.
  • CI mirrors decman's checks: fmt, clippy, tests, docs, cargo-audit, cargo-deny and cargo-machete. Dependabot covers cargo and GitHub Actions.
  • The license is Apache-2.0, the same as decman, because the code comes from decman.

How it was tested

  • 20 unit tests pass. They are the runner and ProbeDiag tests from decman, ported to a stand-in fixture, plus four new tests: a failed step stops the scenario, a class change restarts a streak, ok records an error as transient, and clones share one record.
  • The README example passes as a doctest.
  • cargo fmt --check, cargo clippy -D warnings, cargo doc with -D warnings, cargo audit, cargo deny check advisories and cargo machete all pass locally.
  • decman compiles its full integration suite against this crate through a local path dependency. No phase needed an edit. Its 50 unit tests pass, and clippy is clean.

Follow-up

A decman PR replaces its copy of the runner with this crate. It pins the commit that this PR merges as.

decentralization-manager wrote its integration suite in a
Given/When/Then runner that lived in its test directory. Other repos
could not use the runner without copying it.

This commit moves the generic part of that runner into its own crate.
A small Fixture trait replaces the direct use of decman's fixture type.
Each consumer keeps its own rules for classifying a failed request,
because only the consumer knows its protocol.

CI mirrors decman's checks: fmt, clippy, tests, docs, cargo-audit,
cargo-deny and cargo-machete. Dependabot covers cargo and GitHub
Actions.
@schronck
schronck requested review from scolear and a balanced review from Copilot October 14, 2026 09:25
@socket-security

socket-security Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedtokio@​1.53.35510093100100
Addedanyhow@​1.0.1048110093100100
Addedtracing@​0.1.4410010093100100

View full report

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Probe execution can exceed its deadline indefinitely, and the advisory exception configuration conflicts with CI.

2 open findings
What changed in this PR

Introduces Penelope as a reusable Rust crate for running Given/When/Then scenarios against eventually consistent systems.

Changes:

  • Adds scenario execution, polling, diagnostics, and tests.
  • Documents the public API and usage.
  • Adds licensing, dependency management, and CI automation.
File Description
src/​scenario.rs Implements the scenario runner and tests.
src/​probe.rs Implements shared probe diagnostics.
src/​lib.rs Exposes the public crate API.
README.md Documents installation and usage.
Cargo.toml Defines crate metadata and dependencies.
Cargo.lock Locks dependency versions.
deny.toml Configures advisory checks.
.github/​workflows/​ci.yml Adds Rust CI and security checks.
.github/​dependabot.yml Configures dependency updates.
.gitignore Excludes Rust build artifacts.
LICENSE Adds the Apache-2.0 license.
NOTICE Adds attribution and licensing notice.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/scenario.rs Resolved
Comment thread deny.toml Resolved
The runner checked a Then step's deadline only after a probe returned
None. A probe that never returned kept the scenario pending forever, and
a probe that answered after the deadline still passed the step.

Each probe call now runs under the step's deadline. When the deadline
passes, the runner cancels the call and reports the same timeout error,
with the last recorded probe failure.
CI runs both cargo-audit and cargo-deny, and each reads its own
advisory ignore list. The deny.toml header claimed cargo-deny was the
only gate, so an ignore added there alone would still fail Cargo Audit.

The new .cargo/audit.toml matches decman's layout, and the deny.toml
header now says which file each kind of ignore belongs in.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Core behavior is well tested and coherent; only minor error-message spacing remains.

0 open findings

2 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Low severity Remove trailing spaces from step labels

src/​scenario.rs:50

These trailing spaces are reused in the failure log and error context, whose format strings add another separator. A failing When step is therefore reported as WHEN "..." (and Then would behave the same if this label were used there). Keep labels unpadded; alignment should be applied only by the log formatter if needed.

🧠 Review effort: Balanced

The When and Then labels carried a trailing space so the step log lines
lined up. The failure log and the error context added their own
separator after the label, so a failed When step read `WHEN  "..."`.

The labels are now plain words, and only the step log line pads them to
five characters. The log output is unchanged.
@schronck
schronck merged commit 8f36b2d into main Oct 14, 2026
6 checks passed
@schronck
schronck deleted the feat/core/scenario-runner branch October 14, 2026 09:51
@schronck schronck assigned schronck and unassigned scolear Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants